const library = require("../library/index.js");

module.exports = function(lab) {
    return {
        "@getByAccount": function(account) {

            return lab.sqlite.find("backend_operators", {
                "account": account
            }).then(function(result) {
                this.next(result.records.length ? result.records[0] : null);
            });

        },
        "@checkPasswordByID": function(accountID, password) {
            if (accountID && password) {

                return lab.sqlite.find("backend_operators", accountID).then(function(account) {

                    if (account) {
                        if (library.checkPassword(backend_operator, password)) {
                            this.next();
                        } else {
                            throw @lab.errors.invalid_password;
                        }
                    } else {
                        throw @lab.errors.object_not_found;
                    }

                });

            } else {
                throw @lab.errors.invalid_parameters;
            }
        },
        "@updatePasswordByID": function(accountID, password) {

            if (accountID && password) {

                return lab.find("backend_operators", accountID).then(function(account) {

                    if (account) {
                        library.setupPassword(lab, backend_operator, password).pipe(this);
                    } else {
                        throw @lab.errors.object_not_found;
                    }

                });

            } else {
                throw @lab.errors.invalid_parameters;
            }

        },
        "@updatePassword": function(account, password) {

            if (account && password) {

                return this.@getByAccount(account).then(function(backend_operator) {

                    if (backend_operator) {
                        library.setupPassword(lab, backend_operator, password).pipe(this);
                    } else {
                        throw @lab.errors.object_not_found;
                    }

                })
            } else {
                throw @lab.errors.invalid_parameters;
            }

        },
        "newAccessKey": function(session, expire_date = lab.constants.backend_key_expire_timeout) {
            if (!session.currentUser) {
                throw @lab.errors.not_login;
            }
            return lab.backend.keys.@reauth({
                id: session.currentUser.id,
                name: session.currentUser.name,
                ouid: session.currentOU ? session.currentOU.id : null,
                ou_name: session.currentOU ? session.currentOU.name : null,
                expire_date
            }).then(function(result) {
                this.next(Buffer.concat([Buffer.from(result.id, "hex"), Buffer.from(result.signature, "base64")]).toString("base64"));
            })

        },
        "getProfile": function(session) {
            if (session.currentUser) {
                return lab.find("backend_operators", session.currentUser.id).then(function(operator) {
                    this.next(operator.profile || {});
                });
            } else if (session.participantID) {
                return lab.find("backend_participants", session.participantID).then(function(participant) {
                    this.next(participant ? (participant.profile || {}) : {});
                });
            } else {
                if (!session.backendProfile) {
                    session.backendProfile = {};
                }

                return @.async.resolve(session.backendProfile);
            }
        },
        "updateProfile": function(session, { key, value }) {
            if (session.currentUser) {
                return lab.find("backend_operators", session.currentUser.id).then(function(operator) {
                    if (!operator.profile) {
                        operator.profile = {};
                    }

                    operator.profile[key] = value;
                    return lab.updateWithoutCache("backend_operators", operator).resolve(operator.profile);
                });
            } else if (session.participantID) {
                return lab.find("backend_participants", session.participantID).then(function(participant) {

                    if (participant) {
                        if (!participant.profile) {
                            participant.profile = {};
                        }

                        participant.profile[key] = value;
                        return lab.updateWithoutCache("backend_participants", participant).resolve(participant.profile);

                    } else {

                        if (!session.backendProfile) {
                            session.backendProfile = {};
                        }

                        session.backendProfile[key] = value;
                        return @.async.resolve(session.backendProfile);
                    }

                });
            } else {
                if (!session.backendProfile) {
                    session.backendProfile = {};
                }
                session.backendProfile[key] = value;
                return @.async.resolve(session.backendProfile);
            }
        },
        "updatePassword": function(session, { password_old, password_new }) {
            if (session.currentUser) {

                return lab.find("backend_operators", session.currentUser.id).then(function(operator) {

                    if (library.checkPassword(operator, password_old)) {
                        library.setupPassword(lab, operator, password_new).pipe(this);
                    } else {
                        throw @lab.errors.invalid_password;
                    }
                })

            } else {
                throw @lab.errors.not_login;
            }
        },
        "currentOU": function(session) {

            if (session.currentOU) {

                return @.async.resolve(session.currentOU);

            } else if (session.currentUser && session.currentUser.ouid) {

                return lab.find("backend_operation_units", session.currentUser.ouid).then(function(operation_unit) {

                    if (operation_unit) {
                        session.currentOU = operation_unit;
                    } else {
                        delete session.currentOU;
                    }

                    this.next(operation_unit);
                });

            } else {

                throw @lab.errors.not_login;

            }
        },
        "participant": function(session, form) {

            if (session.participantID && form && session.participantID == form.id) {
                return @.async.resolve({
                    id: session.participantID,
                    ou: session.currentOU,
                    user: session.currentUser,
                })
            }

            return lab.snapshot(function(snapshot) {

                return @.async(function() {

                    if (form && form.id && form.key) {

                        @debug("try to valid paticipant with : " + form.id);

                        snapshot.find("backend_participants", form.id).then(function(current_participant) {

                            if (current_participant && library.verifyKeyAndID(form.id, current_participant.public_key, form.key)) {

                                session.participantID = current_participant.id;

                                if (current_participant.uid) {

                                    snapshot.find("backend_operators", current_participant.uid).then(function(backend_operator) {

                                        if (backend_operator) {
                                            snapshot.backend.user.@doLogin(session, backend_operator).pipe(this);
                                        } else {
                                            throw @lab.errors.object_not_found;
                                        }

                                    }).pipe(this);

                                } else {

                                    this.next({
                                        id: form.id,
                                        key: form.key
                                    });

                                }

                            } else {

                                @warn("paticipant is not valid : " + form.id);
                                library.createKeyAndID(snapshot, session).then(function(result) {
                                    this.next({
                                        id: result.id,
                                        key: result.signature
                                    });
                                }).pipe(this);

                            }

                        }).pipe(this);

                    } else {

                        library.createKeyAndID(snapshot, session).then(function(result) {
                            this.next({
                                id: result.id,
                                key: result.signature
                            });
                        }).pipe(this);

                    }

                })

            })

        },
        "@doLogin": function(session, operator) {

            return @.async(function() {

                delete session.currentOU;
                delete session.currentUser;

                if (operator.ouid) {
                    lab.find("backend_operation_units", operator.ouid).pipe(this);
                } else {
                    this.next();
                }

            }).then(function(operation_unit) {

                session.currentOU = operation_unit;
                session.currentUser = library.exportOperator(operator);

                library.createKeyAndID(lab, session).then(function(result) {

                    this.next({
                        id: result.id,
                        key: result.signature,
                        user: session.currentUser,
                        ou: session.currentOU
                    });

                }).pipe(this);

            })

        },
        "logout": function(session) {

            delete session.currentOU;
            delete session.currentUser;
            delete session.participantID;

            return library.createKeyAndID(lab, session).then(function(result) {
                this.next({
                    id: result.id,
                    key: result.signature
                });
            });
        },
        "register": function(session, { name, account, password, access = []}) {

            if (!session.participantID) {
                throw @lab.errors.not_login;
            }

            if (@options("noRegister")) {
                throw @lab.errors.register_disabled;
            }

            return lab.snapshot(function(snapshot) {

                return @.async(function() {

                    delete session.currentUser;
                    delete session.currentOU;

                    snapshot.backend.users.@register({ name, account, password, access : access }).pipe(this);

                }).then(function(registerResult) {

                    session.currentUser = registerResult.user;
                    session.currentOU = registerResult.ou;

                    library.createKeyAndID(snapshot, session).then(function(paticipantResult) {

                        this.next(@.merge.simple({
                            id: paticipantResult.id,
                            key: paticipantResult.signature
                        }, registerResult));

                    }).pipe(this);
                });

            });
        },
        "login": function(session, { account, password }) {

            if (!session.participantID) {
                throw @lab.errors.not_login;
            }
            if (!account || account.length < 4) {
                throw @lab.errors.account_length;
            }

            if (!password || password.length < 6) {
                throw @lab.errors.password_length;
            }

            return lab.snapshot(function(snapshot) {

                return @.async(function() {

                    snapshot.backend.user.@getByAccount(account).pipe(this);

                }).then(function(existing_user) {

                    if (existing_user && library.checkPassword(existing_user, password)) {
                        this.next(existing_user);
                    } else {
                        throw @lab.errors.account_not_found;
                    }

                }).then(function(backend_operator) {
                    @mew.auto("lab.add_operator_log", {
                        currentUser: backend_operator,
                        target: {},
                        target_id: backend_operator.id,
                        method: "login",
                        kitty: "backend.user",
                        type: "其他",
                        message: `${backend_operator.name} 登录`
                    })
                    snapshot.backend.user.@doLogin(session, backend_operator).pipe(this);
                })

            })
        }
    }
}